#include <coroutine>
#include <thread>
#include <chrono>
#include <functional>
#include <iostream>
#include <future>


//在c++中，只要函数体内出现了'co_await'、'co_yield'或'co_return'这三个关键字之一，这个函数就自动变成了协程
//co_await的作用是让协程“暂停一下”，暂停协程，干别的事情，等条件满足了再回来
//但编译器不知道啥时候算完成，也不知道结果在哪里，所以需要让自定义类型遵守一个规则，这个规则叫Awaitable
//Awaitable就像一份“协程使用说明书“，告诉编译器怎么处理暂停和恢复。它要求你的类型实现三个关键函数：

// await_ready()    //告诉协程“现在能不能直接使用结果？” 
// --> 执行co_await时，协程先问这个函数：“操作是不是已经好了？” 返回true,协程就不用暂停，直接向下执行；返回false,就暂停等在这里
// --> 为什么要有这个函数？因为异步操作的时间不确定

// await_suspend()  //如果要暂停，接下来该干什么？
// -参数：std::coroutine_handle<> (协程的“遥控器”)
// -返回类型：通常是void,也可以是bool
// -作用：如果await_ready()返回false,协程就要暂停，这时就会调用await_suspend()
// -作用: 这个函数拿到一个协程句柄（std::coroutine_handle<>），可以用它在未来的某个时候唤醒协程

//什么是协程句柄？
//它就像协程的身份证，指向当前暂停的协程实例
//调用handle.resume()就能让协程从暂停的地方继续跑

// await_resume()   //恢复时，该返回什么结果？ 
// -返回类型：可以是void,也可以是具体类型
// -作用：当协程恢复执行(或压根没暂停)时，这个函数被调用，它的返回值就是co_await表达式的结果

//这三个函数一起合作，让co_await知道如何暂停、等待和继续
class IntReader{
public:
    bool await_ready(){return false;}

    void await_suspend(std::coroutine_handle<> handle){
        std::thread thread([this, handle](){
            std::this_thread::sleep_for(std::chrono::seconds(2));
            value_ = 1;
            handle.resume();
        });
        thread.detach();
    }

    int await_resume(){return value_;}

private:
    int value_;
};

class Task{
public:
    class promise_type{
    public:
        promise_type():value_(std::make_shared<int>()){}

        //promise_type必须实现的一个函数，它的作用是创建协程的返回值对象
        
        Task get_return_object(){return Task{value_, promis_.get_future()};}

        //刚开始调用协程的时候会去执行initial_suspend,返回suspend_never代表不用暂停，继续往下执行
        std::suspend_never initial_suspend(){return {};}

        std::suspend_never final_suspend()noexcept{return {};}

        void unhandled_exception(){}

        void return_value(int v){
            *value_ = v;
            promis_.set_value();
        }

    private:
        std::shared_ptr<int> value_{};
        std::promise<void> promis_;
    };

public:
    Task(const std::shared_ptr<int>& value, std::future<void> future)
    :value_(value), future_(std::move(future)){}

    int GetValue()const{
        future_.wait();
        return *value_;
    }

private:
    std::shared_ptr<int> value_{};
    std::future<void> future_;
};


//c++对协程的返回类型只有一个硬性规定：它必须包含一个名为'promise_type'的内嵌类型
//当你调用一个协程函数时：
//--> 编译器会在堆上分配空间，保存协程的状态
//--> 同时创建一个'promise_type'对象，嵌在返回类型里
//--> 通过'promise_type'定义的函数，可以控制协程的行为，或者与调用者交换数据

Task GetInt(){//协程
    //在协程函数被调用时，编译器会先创建'promise_type'对象，然后调用'get_return_object'，生成返回类型(比如Task)给调用者


    IntReader reader1;
    int total = co_await reader1;

    IntReader reader2;
    total += co_await reader2;

    IntReader reader3;
    total += co_await reader3;

    //调用co_return时会自动调用promise_type里面的return_value, 把这个total传给return_value
    co_return total;
}

int main(){
    auto task = GetInt();
    std::cout << task.GetValue() << std::endl;

    while(1){}

    return 0;
}